/*
 * @Descripttion: 自定义promise函数 IIFE  es5 立即执行函数 声明一个函数并立马执行
 * @version: 
 * @Author: Zuo
 * @Date: 2021-08-03 10:37:20
 * @LastEditors: Zuo
 * @LastEditTime: 2021-08-04 11:22:43
 */
(function(window){
    /*
        Promise构造函数
        excutor:执行器函数（同步函数）
    */
    function Promise(excutor){
        let self = this;  //将当前promise对象保存起来
        self.status = 'pending'  //给promise对象指定status属性。初始值pending
        self.data = undefined  // 给promise对象指定一个用于存储结果数据的属性
        self.callbacks = []   //每个元素结构：{onResolved(){},onRejected(){}}
        function resolve(value){
            if(self.status != 'pending'){
                return
            }
            //将状态给为resolved
            self.status = 'resolved'  
            //保存value数据
            self.data = value 
            //如果有待执行的callback函数， 异步执行回调onResolved
            if(self.callbacks.length >0 ){
               setTimeout(()=>{
                self.callbacks.forEach(callbacksObj =>{
                    callbacksObj.onResolved(value)
                })
               })
            }
        }
        function reject(reason){
            if(self.status != 'pending'){
                return
            }
            //将状态给为rejected
            self.status = 'rejected'  
            //保存value数据
            self.data = reason 
            //如果有待执行的callback函数， 异步执行回调函数里的OnRejected
            if(self.callbacks.length >0 ){
                setTimeout(()=>{
                    self.callbacks.forEach(callbacksObj =>{
                        callbacksObj.onRejected(reason)
                    })
                })
            }
        }
        //立即执行函数
        try{
            excutor(resolve,reject)
        }catch(errpr){  //如果执行器抛出异常，promise对象变成了rejected
            reject(error)
        }

    }
    /**
     * Promise 原型 对象 的 then()
     * 指定成功和失败的回调函数
     * 返回一个新的promise对象
     * 返回的promise结果由onResolved/onRejected执行结果决定
     */
    Promise.prototype.then = function (onResolved,onRejected){
        //如果then里没有传入成功回调 指定一个默认的成功回调 。 并且把value
        onResolved = typeof onResolved === 'function' ? onResolved : value => value

        //如果then里没有传入失败回调 指定一个默认的失败回调 。 并且把reason抛出 (实现错误/异常穿透的关键点)
        onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}  

        const self = this;

        // 返回一个新的promise对象
        return new Promise((resolve,reject)=>{
            /**
             * 调用指定函数处理，根据执行结果改变这个return的promise状态
             * @param {} callback 
             */
            function handle(callback){
   /*
                    1.如果抛出异常，return的promise就会失败，reason就是error
                    2.如果回调函数返回不是promise，return的promise就会成功，value就是返回的值。
                    3.如果回调函数返回的是promise，return的promise结果就是这个promise的结果。
                    */
                    try{
                        const result = callback(self.data)
                        if(result instanceof Promise){
                         // 3.如果回调函数返回的是promise，return的promise结果就是这个promise的结果。
                         //  result.then(
                         //      value => resolve(value), 
                         //      reason => reject(reason)
                         //  )
 
                         result.then(resolve,reject)  //简写
 
                         /**
                          * 例子解释
                          */
 
                         // function fn (e){
                             
                         // }
                         // div.onclick = function(e){
                         //     fn(e)
                         // }
 
                         // div.onclick = fn
                        }else{
                          //2.如果回调函数返回不是promise，return的promise就会成功，value就是返回的值。
                          resolve(result)
                        }
                    }catch(error){
                     // 1.如果抛出异常，return的promise就会失败，reason就是error
                         reject(error)
                    }
            }
            
            //当前状态还是pending状态，将回调函数保存起来
            if(self.status == 'pending'){
                self.callbacks.push({
                    onResolved(){
                        handle(onResolved)
                    },
                    onRejected(){
                        handle(onRejected)
                    }
                })
            }else if(self.status === 'resolved'){  //当前是resolved状态，异步执行 onResolved 并改变return的promise状态
                setTimeout(()=>{
                    handle(onResolved)
                })
            }else {
                //rejected
                setTimeout(()=>{   //当前是rejected状态，异步执行 onResolved 并改变return的promise状态
                    handle(onRejected)
                })
            }
        })
        
    }
      /**
     * Promise 原型 对象 的 catch()
     * 指定失败的回调函数
     * 返回一个新的promise对象
     */
    Promise.prototype.catch = function (onRejected){
        return this.then(undefined,onRejected)
    }

    /**
     * Promised函数对象的方法resolve
     * 返回指定结果的成功的promise对象
     */
    Promise.resolve = function(value){
        //返回成功/失败的promise
        return new Promise((resolve,reject)=>{
            // value是promise 使用value里的promise结果 作为结果。 
            if(value instanceof Promise){  
                value.then(resolve,reject);
            }else{
                //value不是promise promise变成成功 数据是value
                resolve(value)
            }
        })
    }

    /**
     * Promised函数对象的方法reject
     *  返回指定reason的失败的promise对象
     */
    Promise.reject = function(reason){
        //返回失败的promise
        return new Promise((_,reject)=>{
            reject(reason)
        })
    }

     /**
     * Promised函数对象的方法all  接收的数组
     * 返回一个promise，只有当所有promise都成功才成功，有一个失败就算失败
     */
    Promise.all = function(promises){
        const values = new Array(promises.length) // 用来保存所有成功的value数组
        let resloveCount  = 0;  //记录成功的异步操作进入几次
        return new Promise((resolve,reject)=>{
            //遍历获取每个promise的结果
            promises.forEach((p,index)=>{
               Promise.resolve(p).then(value=>{ // p成功 保存在values里
                    values[index] = value
                    resloveCount ++
                    //如果全部成功了。 调用resolve 传入values
                    if(resloveCount == promises.length){
                        resolve(values);
                    }
                },
                reason =>{  //有一个失败 就return 一个失败
                    reject(reason)
                }
                )
            })
        })
    }


      /**
     * Promised函数对象的方法race  接收数组
     * 返回一个promise，其结果由第一个完成的promise决定
     */
    Promise.race = function(promises){
       return new Promise((resolve,reject)=>{
               //遍历获取每个promise的结果
               promises.forEach((p)=>{
                   // p 可能不是一个promise，需要用Promise.reslove（p） 包装一下 变成一个promise对象。 不影响其原本的值
                Promise.resolve(p).then(value=>{ // 有一个成功  就return 一个成功
                    resolve(value) 
                },
                reason =>{  //有一个失败 就return 一个失败
                    reject(reason)
                }
                )
            })
        })
    }

    /**
     * 返回一个promise对象，它在指定的时间后才确定结果
     */
    Promise.resolveDelay = function (value ,time){
        //返回成功/失败的promise
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                // value是promise 使用value里的promise结果 作为结果。 
                if(value instanceof Promise){  
                    value.then(resolve,reject);
                }else{
                    //value不是promise promise变成成功 数据是value
                    resolve(value)
                }
            },time)
        })
    }

    /**
     * 返回一个promise对象，它在指定的时间后才失败
     */
     Promise.rejectDelay = function (value ,time){
        //返回失败的promise
        return new Promise((_,reject)=>{
            setTimeout(()=>{
                reject(reason)
            },time)
        })
    }


    //向外暴露promise
    window.Promise = Promise
})(window)